﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using XingLucifer.IBase;
using XingLucifer.IBase.Enums;
using System.Net.Sockets;
using System.Net;
using XingLucifer.Devices.BytesFromPropertys.Modbus;
using XingLucifer.Devices.Protocols;

namespace XingLucifer.Devices
{
    public class TCP_Modbus : IDevices
    {
        private ICommunication _com;
        public TCP_Modbus(byte slave_id, ICommunication com)
        {
            com.SetProtocol(new TCP_Modbus_Protocol(slave_id));
            _com = com;
        }

        public TClass ReadClass<TClass>(int address, TClass obj = null, int count = 3) where TClass : class
        {
            if (obj == null) { obj = Activator.CreateInstance<TClass>(); }
            int classSize = (int)StructToBytes.GetClassSize(obj);
            if (classSize > 252)
            {
                throw new Exception("超过Modbus最大字节数");
            }
            byte[] bytes = new byte[5];
            bytes[0] = 0x03;
            bytes[1] = (byte)(address >> 8);
            bytes[2] = (byte)address;
            bytes[3] = (byte)(classSize >> 8);
            bytes[4] = (byte)classSize;
            bytes = _com.SendToRead(bytes, count);
            if (bytes == null) { return default; }
            int boolSize = 0;
            StructToBytes.FromBytes(obj, bytes, ref boolSize, 0, _com.EndianType);
            return obj;
        }

        public bool WriteClass<TClass>(TClass value, int address, int count = 3) where TClass : class
        {
            if (value == null) { throw new Exception("不要传递空对象"); }
            int classSize = (int)StructToBytes.GetClassSize(value);
            if (classSize > 252)
            {
                throw new Exception("超过Modbus最大字节数");
            }
            byte[] array = new byte[classSize];
            List<byte> list = new List<byte>() { 0x10 };
            list.Add((byte)(address >> 8));
            list.Add((byte)address);
            int boolSize = 0;
            StructToBytes.ToBytes(value, array, ref boolSize, 0, _com.EndianType);
            list.Add((byte)((classSize / 2) >> 8));
            list.Add((byte)(classSize / 2));
            list.Add((byte)classSize);
            list.AddRange(array);
            var bytes = _com.SendToRead(list.ToArray(), 3);
            return bytes != null && bytes.Length > 8;
        }

        public TValue ReadSingle<TValue>(int address, int length, int count = 3)
        {
            byte[] bytes = new byte[5];
            bytes[0] = 0x03;
            bytes[1] = (byte)(address >> 8);
            bytes[2] = (byte)address;
            bytes[3] = 0x00;
            Type type = typeof(TValue);
            switch (type.Name)
            {
                case "Int32":
                case "UInt32":
                case "Single":
                    bytes[4] = 2;
                    break;
                case "Double":
                    bytes[4] = 4;
                    break;
                case "Int16":
                case "UInt16":
                    bytes[4] = 1;
                    break;
                case "Boolean":
                case "Byte":
                case "Int64":
                case "UInt64":
                    throw new Exception($"没有实现 {type.Name}");
            }
            bytes = _com.SendToRead(bytes, 3);
            return (TValue)StructToBytes.GetValue(type, bytes, 0, _com.EndianType);
        }

        public bool WriteSingle(object value, int address, int offset, int length, int count = 3)
        {
            Type type = value.GetType();
            if (type.IsArray)
            {
                throw new Exception("请使用Write方法写入数组数据");
            }
            List<byte> list = new List<byte>() { 0x10 };
            list.Add((byte)(address >> 8));
            list.Add((byte)address);
            byte[] bytes = null;
            switch (type.Name)
            {
                case "Int32":
                case "UInt32":
                case "Single":
                    bytes = new byte[4];
                    list.Add(0);
                    list.Add(2);
                    list.Add(4);
                    break;
                case "Double":
                    bytes = new byte[8];
                    list.Add(0);
                    list.Add(4);
                    list.Add(8);
                    break;
                case "Int16":
                case "UInt16":
                    list[0] = 0x06;
                    bytes = new byte[2];
                    break;
                case "Boolean":
                case "Byte":
                case "Int64":
                case "UInt64":
                    throw new Exception($"没有实现 {type.Name}");
                case "String":
                    List<byte> list2 = new List<byte>(Encoding.ASCII.GetBytes((string)value));
                    if (list2.Count % 2 != 0)
                    {
                        list2.Add(0);
                    }
                    list.Add(0);
                    list.Add((byte)(list2.Count / 2));
                    list.Add((byte)list2.Count);
                    if (_com.EndianType == EndianTypes.Modbus_BADC)
                    {

                    }
                    bytes = list2.ToArray();
                    break;
            }
            if (type.Name != "String")
            {
                StructToBytes.GetBytes(value, bytes, 0, _com.EndianType);
            }
            list.AddRange(bytes);
            bytes = _com.SendToRead(list.ToArray(), 3);
            return bytes != null && bytes.Length > 8;
        }

        public Task Read()
        {
            throw new NotImplementedException();
        }

        public bool Open() => _com.Open();

        public void Close() => _com.Close();

        public bool WriteStringAsUInt16(string addr, string values)
        {
            throw new NotImplementedException();
        }

        public bool WriteString(string addr, string values)
        {
            throw new NotImplementedException();
        }

        public bool Write<T>(string addr, T[] values)
        {
            throw new NotImplementedException();
        }

        public bool ReadAndReturnBit(string addr)
        {
            throw new NotImplementedException();
        }

        public List<ushort> Read(string addr, int count)
        {
            throw new NotImplementedException();
        }

        public string ReadString(string addr, int count)
        {
            throw new NotImplementedException();
        }

        string IDevices.Read()
        {
            throw new NotImplementedException();
        }

        public Dictionary<string, string> CircuitTesterReceive()
        {
            throw new NotImplementedException();
        }
    }
}
